package org.hawk.gwt.ppc.reflect.lang;

import java.util.HashSet;
import java.util.Set;

public final class LangClassLoader extends ClassLoaderDelegate {
	public static final String LANG_PACKAGE = "java.lang";

	private static final Class<?>[] LANG_CLASSES = new Class<?>[]{
			Appendable.class,
			ArithmeticException.class,
			ArrayIndexOutOfBoundsException.class,
			ArrayStoreException.class,
			AssertionError.class,
			Boolean.class,
			Byte.class,
			Character.class,
			CharSequence.class,
			Class.class,
			ClassCastException.class,
			ClassNotFoundException.class,
			Cloneable.class,
			Comparable.class,
			Double.class,
			Enum.class,
			Error.class,
			Exception.class,
			Float.class,
			IllegalAccessError.class,
			IllegalAccessException.class,
			IllegalArgumentException.class,
			IllegalStateException.class,
			IndexOutOfBoundsException.class,
			InstantiationException.class,
			Integer.class,
			InternalError.class,
			Iterable.class,
			Long.class,
			Math.class,
			NegativeArraySizeException.class,
			NoSuchFieldException.class,
			NoSuchMethodException.class,
			NullPointerException.class,
			Number.class,
			NumberFormatException.class,
			Object.class,
			Package.class,
			Runnable.class,
			RuntimeException.class,
			Short.class,
			StackTraceElement.class,
			String.class,
			StringBuilder.class,
			StringIndexOutOfBoundsException.class,
			Throwable.class,
			UnsupportedOperationException.class
		};
	
	private static Set<String> classNames;
	
	public static boolean isLangClass(String name){
		if(classNames==null){
			classNames = new HashSet<String>();
			for(Class<?> cls : LANG_CLASSES){
				classNames.add(getSimpleName(cls));
			}
		}
		return classNames.contains(name);
	}
	/**
	 * Performs cast check for the lang classes only
	 * @param src to cast
	 * @param to - class to cast to
	 * @return true if src can be cast to class passed.  
	 */
	static boolean canCast(Object src, Class<?> to) {
		if (to.equals(Appendable.class)) {
			return src instanceof Appendable;
		}
		if (to.equals(ArithmeticException.class)) {
			return src instanceof Appendable;
		}
		if (to.equals(ArrayIndexOutOfBoundsException.class)) {
			return src instanceof Appendable;
		}
		if (to.equals(ArrayStoreException.class)) {
			return src instanceof Appendable;
		}
		if (to.equals(AssertionError.class)) {
			return src instanceof Appendable;
		}
		if (to.equals(Boolean.class) || to.equals(boolean.class)) {
			return src instanceof Boolean;
		}
		if (to.equals(Byte.class) || to.equals(byte.class)) {
			return src instanceof Byte;
		}
		if (to.equals(Character.class) || to.equals(char.class)) {
			return src instanceof Character;
		}
		if (to.equals(CharSequence.class)) {
			return src instanceof CharSequence;
		}
		if (to.equals(Class.class)) {
			return src instanceof Class;
		}
		if (to.equals(ClassCastException.class)) {
			return src instanceof ClassCastException;
		}
		if (to.equals(ClassNotFoundException.class)) {
			return src instanceof ClassNotFoundException;
		}
		if (to.equals(Comparable.class)) {
			return src instanceof Comparable;
		}
		if (to.equals(Cloneable.class)) {
			return src instanceof Cloneable;
		}
		if (to.equals(Double.class) || to.equals(double.class)) {
			return src instanceof Double;
		}
		if (to.equals(Enum.class)) {
			return src instanceof Enum;
		}
		if (to.equals(Error.class)) {
			return src instanceof Error;
		}
		if (to.equals(Exception.class)) {
			return src instanceof Exception;
		}
		if (to.equals(Float.class) || to.equals(float.class)) {
			return src instanceof Float;
		}
		if (to.equals(IllegalAccessError.class)) {
			return src instanceof IllegalAccessError;
		}
		if (to.equals(IllegalAccessException.class)) {
			return src instanceof IllegalAccessException;
		}
		if (to.equals(IllegalArgumentException.class)) {
			return src instanceof IllegalArgumentException;
		}
		if (to.equals(IllegalStateException.class)) {
			return src instanceof IllegalStateException;
		}
		if (to.equals(IndexOutOfBoundsException.class)) {
			return src instanceof IndexOutOfBoundsException;
		}
		if (to.equals(InstantiationException.class)) {
			return src instanceof InstantiationException;
		}
		if (to.equals(Integer.class) || to.equals(int.class)) {
			return src instanceof Integer;
		}
		if (to.equals(InternalError.class)) {
			return src instanceof InternalError;
		}
		if (to.equals(Iterable.class)) {
			return src instanceof Iterable;
		}
		if (to.equals(Long.class) || to.equals(long.class)) {
			return src instanceof Long;
		}
		if (to.equals(NegativeArraySizeException.class)) {
			return src instanceof NegativeArraySizeException;
		}
		if (to.equals(NoSuchFieldException.class)) {
			return src instanceof NoSuchFieldException;
		}
		if (to.equals(NoSuchMethodException.class)) {
			return src instanceof NoSuchMethodException;
		}
		if (to.equals(NullPointerException.class)) {
			return src instanceof NullPointerException;
		}
		if (to.equals(Number.class)) {
			return src instanceof Number;
		}
		if (to.equals(NumberFormatException.class)) {
			return src instanceof NumberFormatException;
		}
		if (to.equals(Package.class)) {
			return src instanceof Package;
		}
		if (to.equals(Runnable.class)) {
			return src instanceof Runnable;
		}
		if (to.equals(RuntimeException.class)) {
			return src instanceof RuntimeException;
		}
		if (to.equals(Short.class) || to.equals(short.class)) {
			return src instanceof Short;
		}
		if (to.equals(StackTraceElement.class)) {
			return src instanceof StackTraceElement;
		}
		if (to.equals(String.class)) {
			return src instanceof String;
		}
		if (to.equals(StringBuilder.class)) {
			return src instanceof StringBuilder;
		}
		if (to.equals(StringIndexOutOfBoundsException.class)) {
			return src instanceof StringIndexOutOfBoundsException;
		}
		if (to.equals(Throwable.class)) {
			return src instanceof Throwable;
		}
		if (to.equals(UnsupportedOperationException.class)) {
			return src instanceof UnsupportedOperationException;
		}
		if (to.equals(Object.class)) {
			return src instanceof Object;
		}
		return false;
	}

	private static String getSimpleName(Class<?> cls) {
		String name = cls.getName();
		int i = name.lastIndexOf('.');
		if(i<0)return name;
		return name.substring(i+1);
	}

	@Override
	protected ClassDelegate<?>[] getClasses() {
		return new ClassDelegate<?>[0];
	}

	@Override
	protected String getPackage() {
		return LANG_PACKAGE;
	}
	
	@Override
	protected Class<?>[] getNotReflectableClasses() {
		return LANG_CLASSES;
	}

	@Override
	protected Class<?>[] getInterfaces() {
		return new Class[0];
	}
}